import json
from pathlib import Path
from PySide6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                               QSplitter, QStatusBar, QToolBar, QMessageBox,
                               QFileDialog, QPushButton)
from PySide6.QtCore import Qt, QSettings
from PySide6.QtGui import QAction, QIcon, QBrush, QColor

from utils.aps_parser import APSParser
from widgets.canvas import AudioCanvas
from widgets.settings_panel import SettingsPanel
from widgets.library_panel import LibraryPanel
from widgets.menu_bar import MenuBar
from widgets.tool_bar import ToolBar
from widgets.node import AudioNode  # 添加这行
from widgets.connection import ConnectionItem  # 添加这行
from dialogs.connection_check_dialog import ConnectionCheckDialog
from dialogs.statistics_dialog import StatisticsDialog
from dialogs.waveform_display import WaveformDisplayWindow
from dialogs.about_dialog import AboutDialog


class AudioProcessorMainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.apsParser = APSParser()
        self.currentFilePath = None
        self.hasUnsavedChanges = False
        self.currentTheme = "dark"

        # 波形显示窗口管理
        self.waveform_windows = {}  # node_id -> window

        # 初始化音频设备管理器
        try:
            from utils.audio_device_manager import AudioDeviceManager
            self.audioDeviceManager = AudioDeviceManager()
        except Exception as e:
            print(f"初始化音频设备管理器时出错: {e}")
            self.audioDeviceManager = None

        # 初始化音频处理引擎
        try:
            from audio_processing.audio_engine import AudioProcessingEngine
            self.audioEngine = AudioProcessingEngine(self.audioDeviceManager)
        except Exception as e:
            print(f"初始化音频处理引擎时出错: {e}")
            self.audioEngine = None

        self.initUI()

        # 连接设置改变信号
        self.settingsPanel.globalSettingsChanged.connect(self.onGlobalSettingsChanged)
        self.settingsPanel.nodeParameterChanged.connect(self.onNodeParameterChanged)

    def initUI(self):
        self.setWindowTitle("音频软件定义处理器")
        self.setGeometry(100, 100, 1200, 800)

        self.createMenuBar()
        self.createToolBar()
        self.createStatusBar()
        self.createCentralWidget()

        # 应用默认主题
        self.applyTheme(self.currentTheme)

        # 设置窗口标题
        self.updateWindowTitle()

    def createMenuBar(self):
        """创建菜单栏"""
        self.menuBar = MenuBar(self)
        self.setMenuBar(self.menuBar)

    def createToolBar(self):
        """创建工具栏"""
        self.toolBar = ToolBar(self)
        self.addToolBar(self.toolBar)

    def createStatusBar(self):
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.showMessage("就绪")

    def createCentralWidget(self):
        centralWidget = QWidget()
        mainLayout = QHBoxLayout(centralWidget)

        # 左侧库面板
        self.libraryPanel = LibraryPanel(self.apsParser)
        self.libraryPanel.setMaximumWidth(200)

        # 中间画布
        self.audioCanvas = AudioCanvas(self.apsParser)

        # 右侧设置面板
        self.settingsPanel = SettingsPanel()
        self.settingsPanel.setMaximumWidth(300)

        # 连接画布点击事件
        self.audioCanvas.scene.selectionChanged.connect(self.onCanvasSelectionChanged)

        # 连接设置面板的信号
        # self.settingsPanel.nodeNameChanged.connect(self.onNodeNameChanged)

        # 分割器
        splitter = QSplitter(Qt.Horizontal)
        splitter.addWidget(self.libraryPanel)
        splitter.addWidget(self.audioCanvas)
        splitter.addWidget(self.settingsPanel)
        splitter.setSizes([200, 600, 300])

        mainLayout.addWidget(splitter)
        self.setCentralWidget(centralWidget)

    # def onNodeNameChanged(self, nodeId, new_name):
    #     """节点名称改变事件"""
    #     # 这里我们只需要标记未保存更改，因为节点名称已经在设置面板中直接设置了
    #     self.markUnsavedChanges()

    def applyTheme(self, theme):
        """应用主题"""
        self.currentTheme = theme

        if theme == "light":
            self.applyLightTheme()
        else:  # dark theme
            self.applyDarkTheme()

        # 更新画布主题
        if hasattr(self, 'audioCanvas'):
            try:
                self.audioCanvas.setTheme(theme)
                # 同时更新画布背景
                if theme == "light":
                    self.audioCanvas.scene.setBackgroundBrush(QBrush(QColor(240, 240, 240)))
                else:
                    self.audioCanvas.scene.setBackgroundBrush(QBrush(QColor(40, 40, 40)))
            except Exception as e:
                print(f"更新画布主题时出错: {e}")

        # 更新音频设备表格
        if hasattr(self, 'settingsPanel'):
            try:
                # 刷新表格以应用新主题
                self.settingsPanel.updateInputTable()
                self.settingsPanel.updateOutputTable()
            except Exception as e:
                print(f"更新音频设备表格主题时出错: {e}")

        # 更新波形查看器窗口主题
        for window in self.waveform_windows.values():
            try:
                if hasattr(window, 'set_theme'):
                    window.set_theme(theme)
            except Exception as e:
                print(f"更新波形窗口主题时出错: {e}")

        # 🔧 新增：更新其他对话框的主题（如果打开的话）
        # 注意：这里我们无法直接访问打开的对话框，但对话框会在创建时应用当前主题

        # 更新状态栏显示
        self.statusBar.showMessage(f"已切换到{'白天' if theme == 'light' else '黑夜'}主题")

    def applyLightTheme(self):
        """应用白天主题"""
        from themes.light_theme import LightTheme
        LightTheme.apply(self)

        # 更新画布背景色
        if hasattr(self, 'audioCanvas') and self.audioCanvas.scene:
            from PySide6.QtGui import QBrush, QColor
            self.audioCanvas.scene.setBackgroundBrush(QBrush(QColor(240, 240, 240)))

        # 更新节点颜色
        self.updateNodesForTheme("light")

        # 更新设置面板中的UUID显示区域样式
        self.updateSettingsPanelForTheme("light")

    def applyDarkTheme(self):
        """应用黑夜主题"""
        from themes.dark_theme import DarkTheme
        DarkTheme.apply(self)

        # 更新画布背景色
        if hasattr(self, 'audioCanvas') and self.audioCanvas.scene:
            from PySide6.QtGui import QBrush, QColor
            self.audioCanvas.scene.setBackgroundBrush(QBrush(QColor(40, 40, 40)))

        # 更新节点颜色
        self.updateNodesForTheme("dark")

        # 更新设置面板中的UUID显示区域样式
        self.updateSettingsPanelForTheme("dark")

    def updateNodesForTheme(self, theme):
        """更新所有节点的颜色以适应主题"""
        if not hasattr(self, 'audioCanvas') or not self.audioCanvas.scene:
            return

        from PySide6.QtGui import QBrush, QColor, QPen
        from PySide6.QtCore import Qt
        from PySide6.QtWidgets import QGraphicsTextItem

        for item in self.audioCanvas.scene.items():
            # 使用属性检查而不是类型检查，避免导入依赖问题
            if hasattr(item, 'nodeData') and hasattr(item, 'nodeType'):
                if theme == "light":
                    # 白天主题：浅色背景，深色边框
                    item.setBrush(QBrush(QColor(240, 240, 240)))
                    item.setPen(QPen(QColor(80, 80, 80), 2))

                    # 更新标题颜色
                    for child in item.childItems():
                        if isinstance(child, QGraphicsTextItem):
                            child.setDefaultTextColor(QColor(0, 0, 0))

                else:  # 黑夜主题
                    # 黑夜主题：深色背景，浅色边框
                    item.setBrush(QBrush(QColor(60, 60, 60)))
                    item.setPen(QPen(QColor(200, 200, 200), 2))

                    # 更新标题颜色
                    for child in item.childItems():
                        if isinstance(child, QGraphicsTextItem):
                            child.setDefaultTextColor(QColor(255, 255, 255))

    # 事件处理方法和项目操作方法的实现...
    def onCanvasSelectionChanged(self):
        """画布选择改变事件"""
        # 添加场景存在性检查
        if not hasattr(self, 'audioCanvas') or not self.audioCanvas.scene:
            self.showGlobalSettings()
            return

        try:
            selectedItems = self.audioCanvas.scene.selectedItems()
            if selectedItems:
                # 检查第一个选中的项是否是节点
                first_item = selectedItems[0]
                # 使用更安全的方式检查是否是节点，避免导入问题
                if hasattr(first_item, 'nodeData') and hasattr(first_item, 'nodeType'):
                    self.showNodeSettings(first_item)
                else:
                    self.showGlobalSettings()
            else:
                self.showGlobalSettings()
        except RuntimeError as e:
            # 处理C++对象已删除的情况
            if "already deleted" in str(e):
                self.showGlobalSettings()
            else:
                raise

    def onGlobalSettingsChanged(self, settings):
        """全局设置改变"""
        self.markUnsavedChanges()

    def onNodeParameterChanged(self, nodeId, paramName, value):
        """节点参数改变"""
        # 移除对父类的调用，因为 QMainWindow 没有这个方法
        # super().onNodeParameterChanged(nodeId, paramName, value)  # 删除这行

        # 标记有未保存的更改
        self.markUnsavedChanges()

        # 更新音频处理器的参数
        if self.audioEngine:
            node = self.audioCanvas.getNodeById(nodeId)
            if node:
                parameters = {paramName: value}
                self.audioEngine.update_processor_parameters(nodeId, parameters)

    def markUnsavedChanges(self):
        """标记有未保存的更改"""
        if not self.hasUnsavedChanges:
            self.hasUnsavedChanges = True
            self.updateWindowTitle()

    def clearUnsavedChanges(self):
        """清除未保存更改标记"""
        self.hasUnsavedChanges = False
        self.updateWindowTitle()

    def updateWindowTitle(self):
        """更新窗口标题"""
        title = "音频软件定义处理器"
        if self.currentFilePath:
            title += f" - {Path(self.currentFilePath).name}"
        if self.hasUnsavedChanges:
            title += " *"
        self.setWindowTitle(title)

    def newProject(self):
        """新建项目"""
        if self.checkUnsavedChanges():
            self.audioCanvas.clearCanvas()
            self.currentFilePath = None
            self.clearUnsavedChanges()
            self.statusBar.showMessage("新建项目")

    def openProject(self):
        """打开项目"""
        if self.checkUnsavedChanges():
            filePath, _ = QFileDialog.getOpenFileName(
                self,
                "打开音频处理项目",
                "",
                "Audio Processor Projects (*.aps)"
            )

            if filePath:
                if self.loadFromFile(filePath):
                    self.currentFilePath = filePath
                    self.clearUnsavedChanges()
                    self.statusBar.showMessage(f"已打开项目: {filePath}")

    def saveProject(self):
        """保存项目"""
        if self.currentFilePath:
            if self.saveToFile(self.currentFilePath):
                self.clearUnsavedChanges()
                return True
        else:
            return self.saveAsProject()
        return False

    def saveAsProject(self):
        """另存为项目"""
        filePath, _ = QFileDialog.getSaveFileName(
            self,
            "保存音频处理项目",
            "",
            "Audio Processor Projects (*.aps)"
        )

        if filePath:
            if not filePath.endswith('.aps'):
                filePath += '.aps'

            if self.saveToFile(filePath):
                self.currentFilePath = filePath
                self.clearUnsavedChanges()
                self.statusBar.showMessage(f"项目已保存: {filePath}")
                return True

        return False

    def checkUnsavedChanges(self):
        """检查未保存的更改"""
        if self.hasUnsavedChanges:
            reply = QMessageBox.question(
                self,
                "未保存的更改",
                "当前项目有未保存的更改，是否保存？",
                QMessageBox.StandardButton.Save |
                QMessageBox.StandardButton.Discard |
                QMessageBox.StandardButton.Cancel
            )

            if reply == QMessageBox.StandardButton.Save:
                return self.saveProject()
            elif reply == QMessageBox.StandardButton.Discard:
                return True
            else:  # Cancel
                return False

        return True

    def saveToFile(self, filePath):
        """保存到文件"""
        try:
            projectData = self.serializeProject()
            with open(filePath, 'w', encoding='utf-8') as f:
                json.dump(projectData, f, indent=2, ensure_ascii=False)
            return True
        except Exception as e:
            QMessageBox.critical(self, "保存错误", f"保存文件时出错: {str(e)}")
            return False

    def loadFromFile(self, filePath):
        """从文件加载"""
        try:
            with open(filePath, 'r', encoding='utf-8') as f:
                projectData = json.load(f)

            return self.deserializeProject(projectData)
        except Exception as e:
            QMessageBox.critical(self, "打开错误", f"打开文件时出错: {str(e)}")
            return False

    def serializeProject(self):
        """序列化项目数据"""
        canvasData = self.audioCanvas.getSerializationData()
        globalSettings = self.settingsPanel.getGlobalSettings()

        # 包含音频设备配置
        audio_devices_data = {}
        if self.audioDeviceManager:
            audio_devices_data = self.audioDeviceManager.get_serializable_data()

        projectData = {
            "version": "1.0",
            "metadata": {
                "name": Path(self.currentFilePath).stem if self.currentFilePath else "Untitled",
                "created": "",
                "modified": ""
            },
            "globalSettings": globalSettings,
            "audioDevices": audio_devices_data,
            "canvas": canvasData
        }
        return projectData

    def deserializeProject(self, projectData):
        """反序列化项目数据"""
        try:
            version = projectData.get("version", "1.0")

            # 设置全局设置
            globalSettings = projectData.get("globalSettings", {})
            self.settingsPanel.setGlobalSettings(globalSettings)

            # 加载音频设备配置
            if 'audioDevices' in projectData and self.audioDeviceManager:
                self.audioDeviceManager.load_from_data(projectData['audioDevices'])
                # 刷新设备表格显示
                self.settingsPanel.updateInputTable()
                self.settingsPanel.updateOutputTable()

            # 加载画布
            canvasData = projectData.get("canvas", {})
            success = self.audioCanvas.loadFromSerializationData(canvasData)

            if success:
                self.showGlobalSettings()

            return success

        except Exception as e:
            print(f"反序列化项目时出错: {e}")
            return False

    def showNodeSettings(self, node):
        """显示节点设置 - 根据运行状态决定是否禁用波形查看器和频谱查看器控件"""
        self.settingsPanel.showNodeSettings(node)

        # 如果是波形查看器或频谱查看器且正在运行，禁用控件
        if (hasattr(node, 'nodeType') and node.nodeType in ['waveform_viewer', 'fft_viewer'] and
                hasattr(self, 'audioEngine') and self.audioEngine and
                hasattr(self.audioEngine, 'is_running') and self.audioEngine.is_running):
            self._disable_current_waveform_settings()

    def showGlobalSettings(self):
        """显示全局设置"""
        self.settingsPanel.showGlobalSettings()

    def runProcessing(self):
        """运行音频处理 - 添加禁用波形查看器设置的功能"""
        if not self.audioEngine:
            self.statusBar.showMessage("音频引擎未初始化")
            return

        try:
            # 🔧 新增：启动前的连接验证
            if not self.validate_connections_before_start():
                # 验证失败，不启动处理
                self.statusBar.showMessage("连接验证失败，无法启动音频处理")
                return

            # 获取全局设置
            global_settings = self.settingsPanel.getGlobalSettings()

            # 设置音频参数
            self.audioEngine.set_audio_settings(
                sample_rate=global_settings['sampleRate'],
                buffer_size=global_settings['bufferSize'],
                channels=global_settings['channelCount']
            )

            # 为所有节点创建处理器
            self._create_processors_for_all_nodes()

            # 构建处理图 - 从画布获取完整数据
            canvas_data = self.audioCanvas.getSerializationData()
            print(f"画布数据: {len(canvas_data.get('nodes', []))} 节点, {len(canvas_data.get('connections', []))} 连接")

            self.audioEngine.build_processing_graph(canvas_data)

            # 🔧 新增：禁用波形查看器的设置控件
            self._disable_waveform_viewer_settings()

            # 启动音频处理
            self.audioEngine.start_processing()

            # 为所有波形查看器节点创建并显示窗口
            self._show_all_waveform_windows()

            self.statusBar.showMessage("音频处理已启动")

        except Exception as e:
            self.statusBar.showMessage(f"启动音频处理时出错: {e}")
            print(f"启动音频处理时出错: {e}")
            import traceback
            traceback.print_exc()
            
    def _show_all_waveform_windows(self):
        """显示所有波形窗口"""
        if hasattr(self, 'audioCanvas') and hasattr(self.audioCanvas, 'getAllNodes'):
            for node in self.audioCanvas.getAllNodes():
                if hasattr(node, 'nodeType'):
                    if node.nodeType == 'waveform_viewer':
                        # 为波形查看器节点创建并显示窗口
                        self._create_waveform_window(node)
                    elif node.nodeType == 'fft_viewer':
                        # 为FFT查看器节点创建并显示窗口
                        self._create_fft_window(node)



    def stopProcessing(self):
        """停止音频处理 - 添加启用波形查看器设置的功能"""
        if self.audioEngine:
            self.audioEngine.stop_processing()
            self.statusBar.showMessage("音频处理已停止")

        # 🔧 新增：启用波形查看器的设置控件
        self._enable_waveform_viewer_settings()

        # 关闭所有波形窗口并释放引用
        self._close_all_waveform_windows()

    def _disable_waveform_viewer_settings(self):
        """禁用所有波形查看器的节点设置面板控件（但不影响波形窗口本身）"""
        # 找到设置面板并禁用波形查看器节点的设置控件
        if hasattr(self, 'settingsPanel') and self.settingsPanel:
            # 通过信号通知设置面板禁用波形查看器设置
            if hasattr(self.settingsPanel, 'setEnabledForWaveformViewers'):
                self.settingsPanel.setEnabledForWaveformViewers(False)
            # 保持现有的禁用逻辑作为后备
            if hasattr(self.settingsPanel, 'currentNode') and self.settingsPanel.currentNode:
                if hasattr(self.settingsPanel.currentNode,
                        'nodeType') and self.settingsPanel.currentNode.nodeType == 'waveform_viewer':
                    self._disable_current_waveform_settings()
        
        # 检查是否有图形管理器并遍历所有节点
        if hasattr(self, 'audioCanvas') and hasattr(self.audioCanvas, 'getAllNodes'):
            for node in self.audioCanvas.getAllNodes():
                if hasattr(node, 'nodeType') and (node.nodeType == 'waveform_viewer' or node.nodeType == 'fft_viewer'):
                    # 现有代码已在选择节点时处理设置面板禁用
                    pass

    def _enable_waveform_viewer_settings(self):
        """启用所有波形查看器的节点设置面板控件"""
        # 找到设置面板并启用波形查看器节点的设置控件
        if hasattr(self, 'settingsPanel') and self.settingsPanel:
            # 通过信号通知设置面板启用波形查看器设置
            if hasattr(self.settingsPanel, 'setEnabledForWaveformViewers'):
                self.settingsPanel.setEnabledForWaveformViewers(True)
            # 保持现有的启用逻辑作为后备
            if hasattr(self.settingsPanel, 'currentNode') and self.settingsPanel.currentNode:
                if hasattr(self.settingsPanel.currentNode,
                        'nodeType') and self.settingsPanel.currentNode.nodeType == 'waveform_viewer':
                    self._enable_current_waveform_settings()
        
        # 检查是否有图形管理器并遍历所有节点
        if hasattr(self, 'audioCanvas') and hasattr(self.audioCanvas, 'getAllNodes'):
            for node in self.audioCanvas.getAllNodes():
                if hasattr(node, 'nodeType') and (node.nodeType == 'waveform_viewer' or node.nodeType == 'fft_viewer'):
                    # 现有代码已在选择节点时处理设置面板启用
                    pass

    def _disable_current_waveform_settings(self):
        """禁用当前设置面板中的波形查看器和频谱查看器控件"""
        try:
            # 禁用参数控件
            for widget in self.settingsPanel.parameterWidgets.values():
                if hasattr(widget, 'setEnabled'):
                    widget.setEnabled(False)

            # 在状态栏显示提示
            self.statusBar.showMessage("音频处理运行中，节点设置已锁定", 3000)

        except Exception as e:
            print(f"禁用查看器设置控件时出错: {e}")

    def _enable_current_waveform_settings(self):
        """启用当前设置面板中的波形查看器和频谱查看器控件"""
        try:
            # 启用参数控件
            for widget in self.settingsPanel.parameterWidgets.values():
                if hasattr(widget, 'setEnabled'):
                    widget.setEnabled(True)

            # 在状态栏显示提示
            self.statusBar.showMessage("音频处理已停止，节点设置已解锁", 3000)

        except Exception as e:
            print(f"启用查看器设置控件时出错: {e}")

    # 移除对波形窗口控件的禁用方法，因为我们要允许波形窗口内部修改
    def _disable_waveform_window_controls(self, window):
        """不再禁用波形显示窗口的控件 - 允许波形窗口内部修改"""
        # 这个方法现在为空，因为我们允许波形窗口在运行时修改参数
        pass

    def _enable_waveform_window_controls(self, window):
        """不再需要启用波形显示窗口的控件 - 因为从未禁用过"""
        # 这个方法现在为空
        pass

    def _close_all_waveform_windows(self):
        """关闭所有波形显示窗口"""
        # 关闭所有波形窗口
        for node_id, window in list(self.waveform_windows.items()):
            try:
                window.close()
                window.deleteLater()
            except Exception as e:
                print(f"关闭波形窗口时出错: {e}")

        # 清空窗口字典，释放引用
        self.waveform_windows.clear()
    
    def _create_fft_window(self, node):
        """为频谱查看器节点创建显示窗口"""
        try:
            from dialogs.fft_display import FFTDisplayWindow

            # 检查是否已经存在窗口
            if node.nodeId in self.waveform_windows:  # 复用现有的waveform_windows字典存储所有查看器窗口
                window = self.waveform_windows[node.nodeId]
                window.show()
                window.activateWindow()
                return

            # 获取节点名称
            node_name = node.getDisplayName()

            # 获取处理器
            processor = self.audioEngine.audio_processors.get(node.nodeId) if self.audioEngine else None

            # 创建显示窗口
            window = FFTDisplayWindow(processor, self)

            # 应用当前主题
            window.apply_dark_theme()  # 使用窗口自身的主题应用方法

            # 存储窗口引用
            self.waveform_windows[node.nodeId] = window

            # 设置处理器的显示窗口
            if processor and hasattr(processor, 'set_display_window'):
                processor.set_display_window(window)
                processor.set_node_name(node_name)

            # 显示窗口
            window.show()
            
        except Exception as e:
            print(f"创建频谱显示窗口时出错: {e}")
            import traceback
            traceback.print_exc()

    def resetProcessing(self):
        """复位音频处理"""
        if self.audioEngine:
            self.audioEngine.reset_all_processors()
            self.statusBar.showMessage("音频处理已复位")

    def _create_processors_for_all_nodes(self):
        """为所有节点创建音频处理器"""
        if not self.audioEngine:
            return

        # 清除现有的处理器
        for node_id in list(self.audioEngine.audio_processors.keys()):
            self.audioEngine.remove_processor(node_id)

        # 为每个节点创建处理器
        nodes = self.audioCanvas.getAllNodes()
        print(f"为 {len(nodes)} 个节点创建处理器")

        for node in nodes:
            node_type = node.nodeType
            parameters = node.parameterValues

            success = self.audioEngine.add_processor(
                node.nodeId,
                node_type,
                parameters
            )

            if success:
                print(f"为节点 {node.getDisplayName()} ({node.nodeId}) 创建了 {node_type} 处理器")

                # 如果是波形查看器或频谱查看器，创建相应的显示窗口
                if node_type == "waveform_viewer":
                    self._create_waveform_window(node)
                elif node_type == "fft_viewer":
                    self._create_fft_window(node)
            else:
                print(f"为节点 {node.getDisplayName()} ({node.nodeId}) 创建处理器失败")

    def _create_waveform_window(self, node):
        """为波形查看器节点创建显示窗口 - 移除运行状态同步"""
        try:
            from dialogs.waveform_display import WaveformDisplayWindow

            # 检查是否已经存在窗口
            if node.nodeId in self.waveform_windows:
                window = self.waveform_windows[node.nodeId]
                window.show()
                window.activateWindow()
                return

            # 获取节点名称
            node_name = node.getDisplayName()

            # 获取处理器
            processor = self.audioEngine.audio_processors.get(node.nodeId) if self.audioEngine else None

            # 创建显示窗口
            window = WaveformDisplayWindow(node_name, processor, self)

            # 🔧 移除：不再同步运行状态到波形窗口
            # if hasattr(self.audioEngine, 'is_running') and self.audioEngine.is_running:
            #     window.set_processing_state(True)

            # 应用当前主题
            window.set_theme(self.currentTheme)

            # 存储窗口引用
            self.waveform_windows[node.nodeId] = window

            # 设置处理器的显示窗口
            if processor and hasattr(processor, 'set_display_window'):
                processor.set_display_window(window)
                processor.set_node_name(node_name)

            print(f"为节点 {node_name} 创建了波形显示窗口")

            # 只在音频处理运行时显示窗口
            if hasattr(self.audioEngine, 'is_running') and self.audioEngine.is_running:
                window.show()

        except Exception as e:
            print(f"创建波形显示窗口时出错: {e}")

    def copySelected(self):
        """复制选中的内容"""
        if hasattr(self, 'audioCanvas'):
            self.audioCanvas.copySelectedContent()

    def cutSelected(self):
        """剪切选中的内容"""
        if hasattr(self, 'audioCanvas'):
            self.audioCanvas.cutSelectedContent()

    def pasteSelected(self):
        """粘贴内容"""
        if hasattr(self, 'audioCanvas'):
            # 粘贴到画布中心
            viewportCenter = self.audioCanvas.viewport().rect().center()
            scenePos = self.audioCanvas.mapToScene(viewportCenter)
            self.audioCanvas.pasteContent(scenePos)

    def deleteSelected(self):
        """删除选中的内容"""
        if hasattr(self, 'audioCanvas'):
            self.audioCanvas.deleteSelectedContent()

    def clearConnections(self):
        """清除所有连接"""
        for item in self.audioCanvas.scene.items():
            # 使用属性检查而不是类型检查
            if hasattr(item, 'startPort') and hasattr(item, 'endPort'):
                item.delete()
        self.markUnsavedChanges()

    def showStatistics(self):
        """显示统计信息 - 确保主题一致"""
        dialog = StatisticsDialog(self.audioCanvas, self)
        # 设置当前主题
        dialog.setTheme(self.currentTheme)
        dialog.exec_()

    def checkConnections(self):
        """检查连接状态 - 确保主题一致"""
        dialog = ConnectionCheckDialog(self.audioCanvas, self)
        # 设置当前主题
        dialog.setTheme(self.currentTheme)
        dialog.exec_()

    def zoomIn(self):
        """放大画布"""
        self.audioCanvas.scale(1.2, 1.2)

    def zoomOut(self):
        """缩小画布"""
        self.audioCanvas.scale(0.8, 0.8)

    def updateSettingsPanelForTheme(self, theme):
        """更新设置面板以适应主题"""
        if not hasattr(self, 'settingsPanel'):
            return

        # 更新UUID显示区域的样式
        if theme == "light":
            uuid_style = """
                QLabel {
                    background-color: #f0f0f0;
                    border: 1px solid #ccc;
                    border-radius: 3px;
                    padding: 5px;
                    font-family: monospace;
                    font-size: 10px;
                    color: #000000;
                }
            """
        else:  # dark theme
            uuid_style = """
                QLabel {
                    background-color: #353535;
                    border: 1px solid #555555;
                    border-radius: 3px;
                    padding: 5px;
                    font-family: monospace;
                    font-size: 10px;
                    color: #ffffff;
                }
            """

        # 应用样式到设置面板中的UUID标签
        # 注意：这需要在设置面板中为UUID标签设置特定的objectName
        # 或者通过查找子控件的方式应用样式

    def closeEvent(self, event):
        """关闭事件"""
        # 确保停止音频处理
        if self.audioEngine:
            self.audioEngine.stop_processing()

        # 关闭所有波形窗口
        self._close_all_waveform_windows()

        super().closeEvent(event)
        if self.checkUnsavedChanges():
            event.accept()
        else:
            event.ignore()

    def getCanvas(self):
        """获取画布引用"""
        return self.audioCanvas

    def getSettingsPanel(self):
        """获取设置面板引用"""
        return self.settingsPanel

    def validate_connections_before_start(self):
        """启动音频处理前的连接验证"""
        if not hasattr(self, 'audioCanvas'):
            return True  # 如果没有画布，跳过验证

        # 获取所有节点
        nodes = self.audioCanvas.getAllNodes()
        errors = []
        warnings = []

        # 检查输出节点的输入连接
        output_nodes = [node for node in nodes if hasattr(node, 'nodeType') and node.nodeType == 'output']
        for node in output_nodes:
            if not node.inputPorts or not any(port.connections for port in node.inputPorts.values()):
                errors.append(f"输出节点 '{node.getDisplayName()}' 没有输入连接，音频将无法输出")

        # 检查波形查看器的输入连接
        waveform_nodes = [node for node in nodes if hasattr(node, 'nodeType') and node.nodeType == 'waveform_viewer']
        for node in waveform_nodes:
            if not node.inputPorts or not any(port.connections for port in node.inputPorts.values()):
                warnings.append(f"波形查看器 '{node.getDisplayName()}' 没有输入连接，将无法显示波形数据")

        # 检查输入节点的输出连接
        input_nodes = [node for node in nodes if hasattr(node, 'nodeType') and node.nodeType == 'input']
        for node in input_nodes:
            if not node.outputPorts or not any(port.connections for port in node.outputPorts.values()):
                warnings.append(f"输入节点 '{node.getDisplayName()}' 没有输出连接，音频数据将被丢弃")

        # 检查是否有孤立节点（没有任何连接的节点）
        for node in nodes:
            has_input_connections = any(port.connections for port in node.inputPorts.values())
            has_output_connections = any(port.connections for port in node.outputPorts.values())

            if not has_input_connections and not has_output_connections:
                warnings.append(f"节点 '{node.getDisplayName()}' 是孤立的，没有输入或输出连接")

        # 显示验证结果
        if errors or warnings:
            return self.show_connection_validation_dialog(errors, warnings)

        return True

    def show_connection_validation_dialog(self, errors, warnings):
        """显示连接验证对话框 - 主题化版本"""
        from PySide6.QtWidgets import QMessageBox

        message = ""
        if errors:
            message += "❌ 错误（阻止启动）:\n" + "\n".join(f"• {error}" for error in errors) + "\n\n"
        if warnings:
            message += "⚠️ 警告:\n" + "\n".join(f"• {warning}" for warning in warnings)

        if not message:
            return True

        msg = QMessageBox(self)

        # 应用主题样式
        if self.currentTheme == "light":
            self._apply_light_theme_to_messagebox(msg)
        else:
            self._apply_dark_theme_to_messagebox(msg)

        if errors:
            msg.setIcon(QMessageBox.Critical)
            msg.setWindowTitle("连接验证 - 错误")
            message += "\n\n请修复错误后再启动音频处理。"
        elif warnings:
            msg.setIcon(QMessageBox.Warning)
            msg.setWindowTitle("连接验证 - 警告")
            message += "\n\n您可以继续启动，但某些功能可能无法正常工作。"

        msg.setText(message)

        if errors:
            # 只有错误时，只显示确定按钮
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
            return False
        else:
            # 只有警告时，提供继续或取消的选择
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg.setButtonText(QMessageBox.Yes, "继续启动")
            msg.setButtonText(QMessageBox.No, "取消")

            reply = msg.exec_()
            return reply == QMessageBox.Yes

    def _apply_light_theme_to_messagebox(self, message_box):
        """应用白天主题到消息框"""
        message_box.setStyleSheet("""
            QMessageBox {
                background-color: #f0f0f0;
                color: #000000;
                font-family: "Microsoft YaHei", "Segoe UI", sans-serif;
            }
            QMessageBox QLabel {
                color: #000000;
                background-color: transparent;
                font-size: 10pt;
                line-height: 1.4;
            }
            QMessageBox QPushButton {
                background-color: #e0e0e0;
                color: #000000;
                border: 1px solid #c0c0c0;
                border-radius: 3px;
                padding: 8px 20px;
                font-weight: bold;
                font-size: 9pt;
                min-width: 80px;
            }
            QMessageBox QPushButton:hover {
                background-color: #d0d0d0;
                border: 1px solid #a0a0a0;
            }
            QMessageBox QPushButton:pressed {
                background-color: #c0c0c0;
            }
            QMessageBox QPushButton:focus {
                outline: 1px solid #8080ff;
            }
        """)

    def _apply_dark_theme_to_messagebox(self, message_box):
        """应用黑夜主题到消息框"""
        message_box.setStyleSheet("""
            QMessageBox {
                background-color: #2b2b2b;
                color: #ffffff;
                font-family: "Microsoft YaHei", "Segoe UI", sans-serif;
            }
            QMessageBox QLabel {
                color: #ffffff;
                background-color: transparent;
                font-size: 10pt;
                line-height: 1.4;
            }
            QMessageBox QPushButton {
                background-color: #404040;
                color: #ffffff;
                border: 1px solid #555555;
                border-radius: 3px;
                padding: 8px 20px;
                font-weight: bold;
                font-size: 9pt;
                min-width: 80px;
            }
            QMessageBox QPushButton:hover {
                background-color: #505050;
                border: 1px solid #777777;
            }
            QMessageBox QPushButton:pressed {
                background-color: #606060;
            }
            QMessageBox QPushButton:focus {
                outline: 1px solid #7777ff;
            }
        """)